import { _decorator, Component, EventTouch, instantiate, Node, NodeEventType, RichText, Size, SpriteFrame, Tween, tween, UITransform, v3, view } from 'cc';
//import { RichTextCheck } from '../../../A-FRAME/component/richtext.check';
import { DataProxy } from '../../../frame/A-LIB/lib.b.data';
import Config from '../../manager/config.manager';
import GameDC from '../../manager/data.game.center';
import GameAssets from '../../manager/game.assets';
const { ccclass, property } = _decorator;

@ccclass('Livecomments')
export class Livecomments extends Component {
	@property(UITransform)
	private view: UITransform = null;
	@property(UITransform)
	private container_sprite: UITransform = null;
	@property(UITransform)
	private container_label: UITransform = null;
	@property(Node)
	private node_prong: Node = null;
	@property([SpriteFrame])
	private channel_sframe: SpriteFrame[] = [];

	private channel_smap: Map<string, SpriteFrame>;

	private type: 'fold'|'unfold' = 'fold';
	private fold_size: Size;
	private view_size: Size;
	private uitrans: UITransform;
	private total_height: number;

	private initedDone: boolean = false;

	protected start(){
		this.init();
		this.initRender();
		this.listening();
	}

	protected update(dt: number): void {
		if(this.frame_call_list.length>0){
			let [call, param, complete] = this.frame_call_list.pop();
			let result = call(...param);
			if(complete) complete(result, ...param);
		}
	}

	private init(){
		this.channel_smap = new Map(this.channel_sframe.map(sframe=>[sframe.name, sframe]));
		this.uitrans = this.node.getComponent(UITransform);
		this.fold_size = this.uitrans.contentSize.clone();
		this.view_size = this.view.contentSize.clone();
		this.type = 'fold';
		this.node.on(NodeEventType.TOUCH_END, this.touchEnd.bind(this));
	}

	private touchEnd(event: EventTouch){
		if(this.type == 'fold') this.unfold();
		else this.fold();
	}

	/** 折叠 */
	private fold(){
		this.type = 'fold';

		[this.uitrans, this.view].forEach(ui=>Tween.stopAllByTarget(ui));

		tween(this.uitrans)
		.to(0.5, {width: this.fold_size.width, height: this.fold_size.height}, {easing: 'quartInOut'})
		.start();

		tween(this.view)
		.to(0.5, {width: this.view_size.width, height: this.view_size.height}, {easing: 'quartInOut'})
		.start();

		Tween.stopAllByTarget(this.node_prong);
		tween(this.node_prong)
		.to(0.5, {scale: v3(1, -1, 1)}, {easing: 'quartInOut'})
		.set({scale: v3(1, -1, 1)}).start();

		mtec.delay(0.5, 'end')
		.then(()=>{
			let count = this.container_sprite.node.children.length;
			for(let i = 0; i < count; i++){
				if(this.type!='fold') break;

				this.container_sprite.node.children[i].children[0].active = i<2;
				this.container_label.node.children[i].children[0].active = i<2;
			}
		});
	}

	/** 展开 */
	private unfold(){
		if(!this.initedDone) return void 0;
		this.type = 'unfold';

		[this.uitrans, this.view].forEach(ui=>Tween.stopAllByTarget(ui));

		tween(this.uitrans)
		.to(0.5, {height: this.total_height}, {easing: 'quartInOut'})
		.start();

		tween(this.view)
		.to(0.5, {height: this.total_height-20}, {easing: 'quartInOut'})
		.start();

		Tween.stopAllByTarget(this.node_prong);
		tween(this.node_prong)
		.to(0.5, {scale: v3(1, 1, 1)}, {easing: 'quartInOut'})
		.set({scale: v3(1, 1, 1)}).start();

		mtec.delay(0, ()=>{
			if(this.type!='unfold') return void 0;
			//this.container_label.node.children.forEach(n=>n.children[0].getComponent(RichTextCheck).adaptThen().then(()=>n.children[0].active = true));
			this.container_label.node.children.forEach(n=>n.children[0].active = true);
			this.container_sprite.node.children.forEach(n=>n.children[0].active = true);
		});
	}

	private initRender(){
		this.total_height = view.getVisibleSize().height - 350;
		//this.total_height = 800;
		let count = Math.ceil(this.total_height / this.container_sprite.height);

		this.frameWhile(mtec.array.create(count, i=>i+1), n=>[this.container_sprite, this.container_label].forEach(ui=>{
			let node = instantiate(ui.node.children[0]);
			node.setParent(ui.node);
			node.setPosition(node.position.x, -(n+1-node.getComponent(UITransform).anchorY) * ui.height, node.position.z);
			node.setSiblingIndex(n);
		})).then(()=>GameDC.getLiveComments(count+1).forWait(async (data, i, ls)=>{
			await this.renderItem(i, data);

			[this.container_label, this.container_sprite]
			.forEach(ui=>ui.node.children[i].children[0].active = false);

			GameDC.Trigger.LiveCommentsProgress = (i+1) + ',' + ls.length;
		})).then(()=>{
			this.initedDone = true;
			this.showNextLater(1);
		});
	}

	private async renderItem(index: number, data: ReturnType<typeof GameDC.getLiveComments>[number]){
		let sprite = this.container_sprite.node.children[index].children[0];
		let richtext = this.container_label.node.children[index].children[0].getComponent(RichText);
		[sprite, richtext.node].forEach(n=>n.active = false);
		richtext.string = '<outline color=#1B1724 width=4>' + GameAssets.getLangText(13,
			data.nickname,
			'<color=#FFBF25>',
			data.count,
			'</color>',
			'<color=#FFBF25>' + Config.symbolString(data.symbol) + '</color>'
		) + '</outline>';
		mtec.cc.skinPeeler(sprite, this.channel_smap.get(data.channel), {width: true});

		//await richtext.getComponent(RichTextCheck).forceAdatptFontSize(false);

		richtext.node.active = this.type == 'unfold';
	}

	private showNextLater(duration: number){
		GameDC.throwAwayLiveComments();

		let time = duration * 0.5;

		let item_height = this.container_label.node.children[0].getComponent(UITransform).height;
		let item_anchorY = this.container_sprite.node.children[0].getComponent(UITransform).anchorY;

		let [target_pos_sprite, target_pos_label] = [this.container_sprite, this.container_label]
		.map(ui=>v3(ui.node.position.x, item_height, ui.node.position.z));

		[this.container_label, this.container_sprite].forEach(ui=>{
			Tween.stopAllByTarget(ui.node);
			[0, 1].forEach(i=>ui.node.children[i].children[0].active = true);
		});

		let np_sprite = new mtec.NudityPromise<'end'>();
		let np_label = new mtec.NudityPromise<'end'>();

		tween(this.container_sprite.node)
		.delay(time).to(time, {position: target_pos_sprite})
		.call(()=>np_sprite.resolve('end')).start();
		tween(this.container_label.node)
		.delay(time).to(time, {position: target_pos_label})
		.call(()=>np_label.resolve('end')).start();

		Promise.all([np_sprite.promise, np_label.promise])
		.then(()=>{
			[this.container_sprite, this.container_label].forEach(ui=>{
				ui.node.setPosition(ui.node.position.x, 0, ui.node.position.z);
				ui.node.children.forEach((item, i)=>item.setPosition(item.position.x, -(i-item_anchorY) * item_height, item.position.z));
			});

			return this.renderItem(0, GameDC.getLiveComments().lastElement);
		}).then(()=>{
			[this.container_sprite, this.container_label].forEach(ui=>{
				let node = ui.node.children[0];
				node.setPosition(node.position.x, -(ui.node.children.length-item_anchorY) * item_height, node.position.z);
				node.setSiblingIndex(ui.node.children.length-1);
				node.children[0].active = this.type=='unfold';
			});
		}).then(()=>this.showNextLater(duration));
	}

	private listening(){
		let round_index = GameDC.User.round;
		DataProxy.follow(GameDC.Trigger, 'UITrans', (_, enter)=>{
			if(enter && round_index!=GameDC.User.round){
				round_index = GameDC.User.round;
				this.refresh();
			}
		}, false);
	}

	private refresh(){
		GameDC.throwAwayLiveComments(Infinity);
		GameDC.getLiveComments(this.container_sprite.node.children.length)
		.forWait((data, i)=>this.renderItem(i, data));
	}

	private frame_call_list: Array<[Function, any[], Function]> = [];
	/**
	 * 下一帧执行的回调
	 * @param call
	 * @param param
	 * @param complete
	 */
	private nextFrameCall<C extends (...args: any)=>any, Param extends Parameters<C>, R extends ReturnType<C>>(call: C, param: Param, complete?: (r: R, ...args: Param)=>void){
		this.frame_call_list.unshift([call, param, complete]);
	}

	/**
	 * 帧循环
	 * @param list 要遍历的数组
	 * @param call 每次遍历的回调
	 */
	private frameWhile<T extends any[]>(list: T, call: (el: T[number], index: number, arr: T)=>void){
		let np = new mtec.NudityPromise<'end'>();
		list.forEach((e, i, a)=>this.nextFrameCall(call, [e, i, list], (_, e, i, a)=>i==a.length-1 ? np.resolve('end') : void 0));
		return np.promise;
	}
}

